package com.springboot.onlinemusicserver.service.imp;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.springboot.onlinemusicserver.mapper.MusicLoveMapper;
import com.springboot.onlinemusicserver.mapper.MusicMapper;
import com.springboot.onlinemusicserver.mapper.UserMapper;
import com.springboot.onlinemusicserver.model.LoginUser;
import com.springboot.onlinemusicserver.model.Music;
import com.springboot.onlinemusicserver.model.MusicLove;
import com.springboot.onlinemusicserver.model.User;
import com.springboot.onlinemusicserver.service.MusicService;
import com.springboot.onlinemusicserver.service.UserService;
import com.springboot.onlinemusicserver.utils.common.CheckParam;
import com.springboot.onlinemusicserver.utils.common.Encrypt;
import com.springboot.onlinemusicserver.utils.common.Result;
import com.springboot.onlinemusicserver.utils.common.SpecialCharacters;
import com.springboot.onlinemusicserver.utils.req.GetMusicParam;
import com.springboot.onlinemusicserver.utils.req.UserLoginParam;
import com.springboot.onlinemusicserver.utils.req.UserRegisterParam;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

import static com.springboot.onlinemusicserver.utils.common.SessionAttribute.USERINFO;

/**
 * Created with IntelliJ IDEA.
 * Description :
 * User: jiume
 * Date: 2025-05-18
 * Time: 19:03
 */
@Slf4j
@Service
public class MusicServiceImp implements MusicService {

    @Resource
    private MusicMapper musicMapper;

    @Resource
    private MusicLoveMapper musicLoveMapper;

    @Value("${music.upload-path}")
    private String path;

    @Transactional // 加上事务，这样即使数据库插入失败，也不会保存前面上传的文件
    @Override
    public Result<Boolean> upload(String singer,
                                  MultipartFile file,
                                  HttpServletRequest request) {
        // 1、校验参数是否合法（歌手是否为空、文件是否为 mp3）
        System.out.println(singer);
        System.out.println(file.getOriginalFilename());
        if (!StringUtils.hasText(singer) || file.isEmpty()) {
            log.info("[upload]: 歌手信息为空或者文件为空");
            return Result.error("歌手信息为空或者文件为空", false);
        }

        try {
            if (!CheckParam.checkUploadParam(file)) {
                log.info("[upload]: 上传的文件不是mp3文件");
                return Result.error("上传的文件不是mp3文件", false);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 2、判断文件是否已经上传过了——查询数据库
        LambdaQueryWrapper<Music> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Music::getSinger, singer);
        List<Music> musicList = musicMapper.selectList(queryWrapper);
        if (!musicList.isEmpty()) {
            // 循环判断列表中是否存在当前歌曲信息
            String originalFilename = file.getOriginalFilename();
            int i = originalFilename.lastIndexOf('.');
            String fileName = originalFilename.substring(0, i);
            for (Music music : musicList) {
                if (music.getMusicName().equals(fileName)) {
                    log.info("[upload]: 该歌曲已经上传过了");
                    return Result.error("该歌曲已经上传过了", false);
                }
            }
        }

        // 2、将文件保存到服务器本地
        // 先得确保 目录存在
        File pathDir = new File(path);
        if (!pathDir.exists()) {
            // 创建多级目录
            if (!pathDir.mkdirs()) {
                log.info("[upload]: 创建目录失败");
                throw new RuntimeException("创建目录失败");
            }
        }
        String originalFilename = file.getOriginalFilename(); // xxx.mp3
        String newPath = path + singer + "/";
        File newDir = new File(newPath);
        if (!newDir.exists()) {
            if (!newDir.mkdirs()) {
                log.info("[upload]: 创建目录失败");
                throw new RuntimeException("创建目录失败");
            }
        }
        File newFile = new File(newPath+originalFilename);
        try {
            // 将获取的文件保存到指定位置
            file.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 3、将上传的文件信息保存到数据库中
        Music music = new Music();
        int i = originalFilename.lastIndexOf('.');
        String fileName = originalFilename.substring(0, i);
        music.setMusicName(fileName);
        music.setSinger(singer);
        // 这里URL存放的是前端Ajax请求的路径
        String url = "/music/get?path="+singer+"/"+fileName;
        music.setUrl(url);
        LoginUser user = (LoginUser) request.getSession(false).getAttribute(USERINFO);
        music.setUserId(user.getUserId());
        int result = musicMapper.insert(music);
        if (result != 1) {
            log.info("[upload]: 插入失败");
            return Result.error("文件无法保存到数据库中", false);
        }
        log.info("[upload]: 插入成功");
        return Result.success(true);
    }

    @Override
    public ResponseEntity<byte[]> getMusic(String musicPath) {
        // 1、校验参数是否合法
        if (!StringUtils.hasText(musicPath)) {
            log.info("[getMusic]: 音乐文件路径参数为空");
            return ResponseEntity.badRequest().build();
        }
        String singer = musicPath.split("/")[0]; // zhangsan
        String musicName = musicPath.split("/")[1]; // 陈势安 － 天后.mp3
        // 2、查询数据库
        LambdaQueryWrapper<Music> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Music::getSinger, singer)
                .eq(Music::getMusicName, musicName.substring(0, musicName.lastIndexOf(".")));
        List<Music> musicList = musicMapper.selectList(queryWrapper);
        if (musicList.isEmpty()) {
            log.info("[getMusic]: 不存在这样的歌曲信息");
            return ResponseEntity.badRequest().build();
        }
        // 3、构造文件路径，查找具体文件
        String filePath = path + musicPath; // 这里不需要加上后缀 .mp3
        // 读取该文件的所有内容转换为字节流
        byte[] target = null;
        try {
            // Paths.get(filePath) <=> Path path = Paths.get(filePath)
            target = Files.readAllBytes(Paths.get(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (target == null || target.length == 0) {
            log.info("[getMusic]: 文件内容为空");
            return ResponseEntity.badRequest().build();
        }
        log.info("[getMusic]: 音乐——"+musicName+" 获取成功");
        return ResponseEntity.ok(target);
    }

    @Transactional // 加上事务，一旦出现异常，可以恢复数据库中的信息
    @Override
    public Result<Boolean> deleteMusic(Long musicId) {
        // 1、校验参数是否合法（不为空且大于0）
        if (musicId == null || musicId <= 0) {
            log.info("[deleteMusic]: 参数不合法");
            return Result.error("参数不合法", false);
        }
        // 2、查询数据库
        List<Music> musicList = musicMapper.selectByIds(List.of(musicId));
        if (musicList.isEmpty()) {
            log.info("[deleteMusic]: 要删除的音乐不存在");
            return Result.error("要删除的音乐不存在", false);
        }
        // 3、删除数据库中音乐信息
        LambdaUpdateWrapper<Music> updateWrapper = new LambdaUpdateWrapper<>();
        // update music set status = 1 where music_id = 1;
        updateWrapper.set(Music::getStatus, 1).eq(Music::getMusicId, musicId);
        int result = musicMapper.update(updateWrapper);
        if (result != 1) {
            log.info("[deleteMusic]: 数据库删除失败");
            return Result.error("数据库删除失败", false);
        }
        // 接下来需要删除music_love表中的音乐信息
        // 先去查看music_love表中是否存在该音乐信息
        LambdaQueryWrapper<MusicLove> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MusicLove::getMusicId, musicId);
        List<MusicLove> musicLoves = musicLoveMapper.selectList(queryWrapper);
        // 不存在该音乐，就无需删除
        if (!musicLoves.isEmpty()) {
            LambdaUpdateWrapper<MusicLove> updateWrapperLoveMusic = new LambdaUpdateWrapper<>();
            updateWrapperLoveMusic.set(MusicLove::getStatus, 1).eq(MusicLove::getMusicId, musicId);
            result = musicLoveMapper.update(updateWrapperLoveMusic);
            if (result != 1) {
                log.info("[deleteMusic]: 数据库删除失败");
                return Result.error("数据库删除失败", false);
            }
        }
        // 4、删除服务器本地磁盘中的音乐
        // 先构造path路径
        Music music = musicList.get(0);
        String filePath = path + music.getSinger() + "/" + music.getMusicName() + ".mp3";
        File file = new File(filePath);
        boolean deleteResult = file.delete();
        if (!deleteResult) {
            log.info("[deleteMusic]: 服务器删除失败");
            return Result.error("服务器删除失败", false);
        }
        log.info("[deleteMusic]: music_id为 "+musicId+" 的音乐删除成功");
        return Result.success(true);
    }

    @Transactional // 加上事务，一旦出现异常，可以恢复数据库中的信息
    @Override
    public Result<Boolean> deleteBatchMusic(List<Long> musicIds) {
        // 1、校验参数是否合法
        if (!CheckParam.checkDeleteBatchParam(musicIds)) {
            log.info("[deleteBatchMusic]: 参数不合法");
            return Result.error("参数不合法");
        }
        // 2、循环删除单个文件的逻辑
        for (Long musicId : musicIds) {
            // 1)查询数据库看是否存在该音乐
            List<Music> musicList = musicMapper.selectByIds(List.of(musicId));
            if (musicList.isEmpty()) {
                log.info("[deleteMusic]: 要删除的音乐不存在");
                return Result.error("要删除的音乐不存在", false);
            }
            // 2)删除数据库中音乐信息
            LambdaUpdateWrapper<Music> updateWrapper = new LambdaUpdateWrapper<>();
            // update music set status = 1 where music_id = 1;
            updateWrapper.set(Music::getStatus, 1).eq(Music::getMusicId, musicId);
            int result = musicMapper.update(updateWrapper);
            if (result != 1) {
                log.info("[deleteMusic]: 数据库删除失败");
                return Result.error("数据库删除失败", false);
            }
            // 接下来需要删除music_love表中的音乐信息
            // 先去查看music_love表中是否存在该音乐信息
            LambdaQueryWrapper<MusicLove> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(MusicLove::getMusicId, musicId);
            List<MusicLove> musicLoves = musicLoveMapper.selectList(queryWrapper);
            // 不存在该音乐，就无需删除
            if (!musicLoves.isEmpty()) {
                LambdaUpdateWrapper<MusicLove> updateWrapperLoveMusic = new LambdaUpdateWrapper<>();
                updateWrapperLoveMusic.set(MusicLove::getStatus, 1).eq(MusicLove::getMusicId, musicId);
                result = musicLoveMapper.update(updateWrapperLoveMusic);
                if (result != 1) {
                    log.info("[deleteMusic]: 数据库删除失败");
                    return Result.error("数据库删除失败", false);
                }
            }
            // 3)删除服务器本地磁盘中的音乐
            // 先构造path路径
            Music music = musicList.get(0);
            String filePath = path + music.getSinger() + "/" + music.getMusicName() + ".mp3";
            File file = new File(filePath);
            boolean deleteResult = file.delete();
            if (!deleteResult) {
                log.info("[deleteMusic]: 服务器删除失败");
                return Result.error("服务器删除失败", false);
            }
        }
        log.info("[deleteMusic]: music_id为 "+musicIds+" 的音乐批量删除成功");
        return Result.success(true);
    }

    @Override
    public Result<List<Music>> selectMusicList(String selectName) {
        // 1、判断查询参数是否为空，根据其值来判断进行哪种查询
        List<Music> musicList = null;
        if (selectName == null) {
            // 查询所有
            List<Music> result = musicMapper.selectList(null);
            return Result.success(result);
        } else {
            // 根据参数模糊查询
            LambdaQueryWrapper<Music> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.like(Music::getMusicName, selectName);
            List<Music> result = musicMapper.selectList(queryWrapper);
            return Result.success(result);
        }
    }
}
